/*
					ORDENACAO DE VETOR UTILIZANDO SOCKETS EM C
 =======================================================================================
 Nome        : NivelSup.c
 Autores     : Eduardo Aramizu, Matheus Zoccoler
 Disciplina  : SSC0640 – Sistemas Computacionais Distribuídos (Engenharia de Computacao)
 Descricao   : O programa define o funcionamento do no de nivel 4 ou Servidor Principal.
				Ele recebe dois vetores de tamanho 500 gerados nos nos de nivel 3 (Nivel
				Int2.c) e ordena pelo metodo QuickSort. O resultado e' entao enviado aos
				nos de nivel 3.	
 =======================================================================================
 */
#ifndef ALL_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>   // Definicao de tipos
#include <sys/socket.h>  // Biblioteca de estrutara de sockets
#include <netinet/in.h>  // Define os padroes de protocolo IP
#include <arpa/inet.h>   // Converte enderecos hosts
#include <string.h>
#include <unistd.h> // Define constantes POSIX
#include <errno.h>  // Utilizado para capturar mensagens de erro
#include <netdb.h>
#define ALL_H_INCLUDED
#endif

#ifndef OPERATIONS_H_INCLUDED
#include "Operacoes.h"
#endif

#define RCVSIZE 500

int main(int argc, char *argv[])
{
    int sock, connected_r, connected_l, bytes_recv, i, true = 1;
    int rcvArray[2*RCVSIZE];
    struct sockaddr_in server_addr, client_addr;
    int sin_size;

    struct timeval t1,t2;
    int time;
    FILE *f;
    f = fopen(argv[2], "w");

    /********** INICIA SERVIDOR NA PORTA ESPECIFICADA ************/
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("Erro de Socket");
        exit(1);
    }

    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &true,sizeof(int)) == -1)
    {
        perror("Erro Setsockopt");
        exit(1);
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(argv[1]));    //Servidor escuta na porta de argv[1]
    server_addr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(server_addr.sin_zero),8);

    if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
    {
        perror("Nao foi possivel realizar o bind");
        exit(1);
    }


    if (listen(sock, 10) == -1)
    {
        perror("Erro de Listen");
        exit(1);
    }

    /********** RECEBE DOS NIVEIS INF ************/
    printf("\nServidor TCP esperando por conexoes na porta %s\n", argv[1]);

    int cont = 0;
    while(cont < 2)
    {
        sin_size = sizeof(struct sockaddr_in);

        if(cont == 0)
        {
            connected_l = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
            printf("\nConexão aceita de (%s , %d)\n", inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port));

            gettimeofday(&t1, 0);   //Tempo antes do receive
            bytes_recv=recv(connected_l,rcvArray,RCVSIZE*4, MSG_WAITALL);
            gettimeofday(&t2, 0);   //Tempo depois do receive
            time = t2.tv_usec-t1.tv_usec;
            fprintf(f,"\nTempo recebimento do inferior 1:  %.2dus.\n", time);
        }
        else
        {
            connected_r = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
            printf("\nConexão aceita de (%s , %d)\n", inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port));

            gettimeofday(&t1, 0);   //Tempo antes do receive
            bytes_recv=recv(connected_r,rcvArray+RCVSIZE,RCVSIZE*4, MSG_WAITALL);   //Escreve na frente do primeiro vetor
            gettimeofday(&t2, 0);   //Tempo depois do receive
            time = t2.tv_usec-t1.tv_usec;
            fprintf(f,"\nTempo recebimento do inferior 2:  %.2dus.\n", time);
        }

        printf("\nMensagem recebida: \n");

        cont++;
    }

    /********** ORDENA VETORES RECEBIDOS ************/
    gettimeofday(&t1, 0);   //Tempo antes da ordenacao
    quickSort(rcvArray, 2*RCVSIZE);
    gettimeofday(&t2, 0);   //Tempo depois da ordenacao
    time = t2.tv_usec-t1.tv_usec;
    fprintf(f,"\nTempo ordenacao:  %.2dus.\n", time);

    /*for(i=0; i<2*RCVSIZE; i++)
        printf("%d\n", rcvArray[i]);*/

    /********** ENVIA AOS NIVEIS INF ************/
    gettimeofday(&t1, 0);   //Tempo antes do send
    send(connected_l,rcvArray,2*RCVSIZE*4, 0);
    gettimeofday(&t2, 0);   //Tempo depois do send
    time = t2.tv_usec-t1.tv_usec;
    fprintf(f,"\nTempo envio ao inferior 1:  %.2dus.\n", time);

    gettimeofday(&t1, 0);   //Tempo antes do send
    send(connected_r,rcvArray,2*RCVSIZE*4, 0);
    gettimeofday(&t2, 0);   //Tempo depois do send
    time = t2.tv_usec-t1.tv_usec;
    fprintf(f,"\nTempo envio ao inferior 2:  %.2dus.\n", time);

    //Fecha conexoes com inferiores
    close(connected_l);
    close(connected_r);

    fclose(f);

    return 0;
}
